﻿package extremefx.ui {
	import extremefx.IEnumerator;
	import extremefx.collections.MirrorMap;
	import extremefx.geom.Size;
	import extremefx.ui.layout.ILayoutManager;
	
	import flash.display.DisplayObjectContainer;	

	/**
	 * @author Marcelo Volmaro
	 */
	public class Container extends Component {
		private static var _nameIndex:uint = 0;
		private var _needsRelayout:Boolean;
		protected var _components:MirrorMap;
		protected var _layout:ILayoutManager;
		internal var _containerTabGroup:TabGroup;

		public function Container() {
			_components = new MirrorMap();
			_needsRelayout = false;
			_kind = "Container";
			_containerTabGroup = new TabGroup(this); 
			_tabEnabled = true;
			super();
		}

		public function attachToDisplay(pDisplayObject:DisplayObjectContainer):void {
			pDisplayObject.addChild(_visualUI);
		}

		public function removeFromDisplay():void {
			if (_visualUI.parent is DisplayObjectContainer) {
				_visualUI.parent.removeChild(_visualUI);
			}
		}
		
		public function getTabGroup():TabGroup {
			return _containerTabGroup;
		}

		override protected function _draw():void {
			if (_layout is ILayoutManager) {
				_layout.layoutContainer(this);
			}

			_needsRelayout = false;
			
			_visualUI.x = _x;
			_visualUI.y = _y;
		}

		override protected function _onSizeChange():void {
			_needsRelayout = true;
		}

		override public function get preferredSize():Size {
			if (_layout is ILayoutManager) return _layout.preferredLayoutSize(this);
			return super.preferredSize;
		}

		override public function get minimumSize():Size {
			if (_layout is ILayoutManager) return _layout.minimumLayoutSize(this);
			return super.minimumSize;
		}

		/**
		 * Gets the layout manager for this container.
		 */
		public function get layoutManager():ILayoutManager {
			return _layout;
		}

		/**
		 * Sets the layout manager for this container.
		 */
		public function set layoutManager(pLayoutManager:ILayoutManager):void {
			_removeAllFromLayout();

			if (pLayoutManager is ILayoutManager) {
				var e:IEnumerator = _components.getEnumerator();
				
				while(e.moveNext()) {
					pLayoutManager.addComponent(e.current.key, e.current.value);
				}
			}
			
			_layout = pLayoutManager;
			_needsRelayout = true;
		}

		/**
		 * Gets all the components in the Container.
		 * @return an Array of <code>KeyValuePair</code> containing the component name / component object.
		 */
		public function getComponents():Array {
			return _components.toArray();
		}

		/**
		 * Adds the specified component to the end of this container. 
		 * Also notifies the layout manager to add the component to this container's layout.
		 */
		public function add(pComponent:Component, pName:String = ""):void {
			pName = pName || pComponent.name || ("$$cmp$$" + (_nameIndex++));
			pComponent.name = pName;
			
			_components.add(pName, pComponent);
			pComponent.parent = this;
			
			if (_layout) {
				_layout.addComponent(pName, pComponent);
			}
			
			_visualUI.addChild(pComponent._visualUI);
		}

		/**
		 * Removes the specified component from this container. 
		 * This method also notifies the layout manager to remove the component from this container's layout 
		 * via the removeLayoutComponent method.
		 */
		public function remove(pComponent:Component):void {
			pComponent.parent = null;
			_components.removeValue(pComponent);
			if (_layout) {
				_layout.removeComponent(pComponent);
			}
		}

		public function removeAll():void {
			_removeAllFromLayout();
			var e:IEnumerator = _components.getEnumerator(); 
			var c:Component;
			while(e.moveNext()) {
				c = e.current.value as Component;
				c.parent = null;
			}
			
			_components.clear();
		}

		private function _removeAllFromLayout():void {
			var e:IEnumerator, c:Component;
			if (_layout is ILayoutManager) {
				e = _components.getEnumerator();
				
				while(e.moveNext()) {
					c = e.current.value as Component;
					_layout.removeComponent(c);
				}
			}
		}

		override public function dispose():void {
			if (_disposing) return;
			super.dispose();
			
			if (_layout) _layout.dispose();
			_layout = null;
			removeAll();
			_components.dispose();
		}
	}
}
